#include "XDecode.h"
#include <iostream>
#include <QDebug>
extern "C"
{
#include<libavcodec/avcodec.h>
}
using namespace std;

void XDecode::Close()
{
	decodemux.lock();
	if (codec != NULL) {
		avcodec_close(codec);
		avcodec_free_context(&codec);
		qDebug() << "success to close AVcodecContext";
	}
	decodemux.unlock();
}
void XDecode::Clear()
{
	decodemux.lock();
	//清理解码缓冲
	if (codec != NULL) {
		avcodec_flush_buffers(codec);
		qDebug() << "success to flush buffers";
	}
	
	decodemux.unlock();
}
bool XDecode::Open(AVCodecParameters * para)
{
	if (para == NULL) {
		return false;
	}
	Close();
	///解码器打开
	///找到解码器
	AVCodec *vcodec = avcodec_find_decoder(para->codec_id);
	if (!vcodec)
	{
		avcodec_parameters_free(&para);
		qDebug() << "para codec id" << para->codec_id;
		qDebug() << "para codec type" << para->codec_type;
		//avcodec_parameters_free(&para);
		qDebug() << "can't find the codec id " << para->codec_id;
		return false;
	}
	qDebug() << "para codec id" << para->codec_id;
	qDebug() << "para codec type" << para->codec_type;

	decodemux.lock();
	codec = avcodec_alloc_context3(vcodec);

	///配置解码器上下文参数
	avcodec_parameters_to_context(codec, para);
	avcodec_parameters_free(&para);
	//八线程解码
	codec->thread_count = 8;

	///打开解码器上下文
	int re = avcodec_open2(codec, 0, 0);
	if (re != 0)
	{
		qDebug() << "flag3";
		avcodec_free_context(&codec);
		decodemux.unlock();
		char buf[1024] = { 0 };
		av_strerror(re, buf, sizeof(buf) - 1);
		qDebug() << "avcodec_open2  failed! :" << buf;
		return false;
	}
	decodemux.unlock();
	qDebug() << "codec_open2 success!" << endl;
	return true;
	
}

//发送到解码线程，不管成功与否都释放pkt空间(对象和媒体内容);
bool XDecode::Send(AVPacket *pkt)
{
	//容错处理
	if (!pkt || pkt->size <= 0 || !pkt->data) {
		qDebug() << "error para handle";
		return false;
	}
	decodemux.lock();
	if (!codec) {
		qDebug() << "flag1";
		decodemux.unlock();
		return false;
	}
	int re = avcodec_send_packet(codec, pkt);
	decodemux.unlock();
	av_packet_free(&pkt);
	if (re != 0) {
		qDebug() << "flag2";
		return false;
	}
	return true;
}

//获取解码数据，一次send可能需要多次Recv获取缓冲区中的数据Send， NUll再recv多次
//每次复制一份，要由调用者释放 av_frame_free
AVFrame* XDecode::Recv()
{
	decodemux.lock();
	if (codec == NULL) {
		decodemux.unlock();
		qDebug() << "codec is NULL";
		return NULL;
	}
	AVFrame *frame = av_frame_alloc();
	int re = avcodec_receive_frame(codec, frame);
	decodemux.unlock();
	if (re != 0) {
		av_frame_free(&frame);
		return NULL;
	}
	//qDebug() << "frame_linesize" << frame->linesize[0] <<flush;
	pts = frame->pts;
	return frame;
}


XDecode::XDecode()
{
}

XDecode::~XDecode()
{
}
